package com.ygp.dtp.core.notify.abstracts;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import com.ygp.dtp.common.constant.DynamicTpConstant;
import com.ygp.dtp.common.dto.DynamicThreadPoolMainProperty;
import com.ygp.dtp.common.dto.Instance;
import com.ygp.dtp.common.dto.NotifyItem;
import com.ygp.dtp.common.dto.NotifyPlatform;
import com.ygp.dtp.common.enums.NotifyTypeEnum;
import com.ygp.dtp.common.enums.RejectedTypeEnum;
import com.ygp.dtp.common.holder.ApplicationContextHolder;
import com.ygp.dtp.core.DynamicThreadPoolRegistry;
import com.ygp.dtp.core.context.DynamicThreadPoolContext;
import com.ygp.dtp.core.context.DynamicThreadPoolContextHolder;
import com.ygp.dtp.core.notify.Notifier;
import com.ygp.dtp.core.notify.NotifyHelper;
import com.ygp.dtp.core.thread.DynamicThreadPoolExecutor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.core.env.Environment;

import java.lang.reflect.Field;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @description: 抽象通知类，二级缓冲类
 * @motto: 代码源于生活，高于生活艺术
 * @author: zhouhengzhe
 * @date: 2022/8/9 15:41
 * @since 1.0
 **/
@Slf4j
public abstract class AbstractNotifier implements Notifier {

    private static Instance instance;

    public static Instance getInstance() {
        return instance;
    }

    public AbstractNotifier() {
        init();
    }

    /**
     * 初始化
     */
    public static void init() {
        try {
            //环境变量
            Environment environment = ApplicationContextHolder.getEnvironment();
            //应用名（旧）
            String appName = environment.getProperty(DynamicTpConstant.SPRING_APPLICATION_NAME);
            //端口
            String serverPort = environment.getProperty(DynamicTpConstant.SERVER_PORT);
            //ip地址
            String hostAddress = InetAddress.getLocalHost().getHostAddress();
            //激活的文件
            String[] activeProfiles = environment.getActiveProfiles();
            if (ArrayUtils.isEmpty(activeProfiles)) {
                activeProfiles = environment.getDefaultProfiles();
            }
            //创建实例ip相关信息
            instance = Instance
                    .builder()
                    .ip(hostAddress)
                    .port(StringUtils.isNotBlank(serverPort) ? Integer.parseInt(serverPort) : 0)
                    .serviceName(StringUtils.isNotBlank(appName) ? appName : DynamicTpConstant.DEFAULT_SPRING_APPLICATION_NAME)
                    .env(activeProfiles[0])
                    .build();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
    }

    /**
     * 构建告警内容
     *
     * @param platform 平台
     * @param template 模板
     * @param typeEnum 通知类型：配置改变提醒，线程池存活提醒
     * @return
     */
    public String buildAlarmContent(NotifyPlatform platform, NotifyTypeEnum typeEnum, String template) {
        DynamicThreadPoolContext dynamicThreadPoolContext = DynamicThreadPoolContextHolder.get();
        String threadPoolName = getThreadPoolName(dynamicThreadPoolContext);
        DynamicThreadPoolExecutor dynamicThreadPoolExecutor = DynamicThreadPoolRegistry.getExecutor(threadPoolName);
        List<String> receivers = StrUtil.split(platform.getReceivers(), ",");
        //电话号码/企微名称
        String receiverStr = Joiner.on(", @").join(receivers);
        NotifyItem notifyItem = dynamicThreadPoolContext.getNotifyItem();
        //组装警告信息
        String content = String.format(
                template,
                getInstance().getServiceName(),
                getInstance().getIp() + ":" + getInstance().getPort(),
                getInstance().getEnv(),
                dynamicThreadPoolExecutor.getThreadPoolName(),
                typeEnum.getCode(),
                notifyItem.getThreshold(),
                dynamicThreadPoolExecutor.getCorePoolSize(),
                dynamicThreadPoolExecutor.getMaximumPoolSize(),
                dynamicThreadPoolExecutor.getPoolSize(),
                dynamicThreadPoolExecutor.getActiveCount(),
                dynamicThreadPoolExecutor.getLargestPoolSize(),
                dynamicThreadPoolExecutor.getTaskCount(),
                dynamicThreadPoolExecutor.getCompletedTaskCount(),
                dynamicThreadPoolExecutor.getQueue().size(),
                dynamicThreadPoolExecutor.getQueueName(),
                dynamicThreadPoolExecutor.getQueueCapacity(),
                dynamicThreadPoolExecutor.getQueue().size(),
                dynamicThreadPoolExecutor.getQueue().remainingCapacity(),
                RejectedTypeEnum.formatRejectName(dynamicThreadPoolExecutor.getRejectHandlerName()),
                dynamicThreadPoolExecutor.getRejectCount(),
                receiverStr,
                DateUtil.now(),
                notifyItem.getInterval()
        );
        //突出显示报警内容
        return highlightAlarmContent(content, typeEnum);
    }

    /**
     * 构建通知内容
     *
     * @param platform 平台
     * @param template 模板
     * @param oldProp  旧配置
     * @param diffs    差异配置
     * @return
     */
    public String buildNoticeContent(NotifyPlatform platform,
                                     String template,
                                     DynamicThreadPoolMainProperty oldProp,
                                     List<String> diffs) {
        String threadPoolName = oldProp.getDtpName();
        DynamicThreadPoolExecutor dtpExecutor = DynamicThreadPoolRegistry.getExecutor(threadPoolName);

        List<String> receivers = StrUtil.split(platform.getReceivers(), ',');
        String receivesStr = Joiner.on(", @").join(receivers);

        String content = String.format(
                template,
                getInstance().getServiceName(),
                getInstance().getIp() + ":" + getInstance().getPort(),
                getInstance().getEnv(),
                threadPoolName,
                oldProp.getCorePoolSize(),
                dtpExecutor.getCorePoolSize(),
                oldProp.getMaxPoolSize(),
                dtpExecutor.getMaximumPoolSize(),
                oldProp.isAllowCoreThreadTimeOut(),
                dtpExecutor.allowsCoreThreadTimeOut(),
                oldProp.getKeepAliveTime(),
                dtpExecutor.getKeepAliveTime(TimeUnit.SECONDS),
                dtpExecutor.getQueueName(),
                oldProp.getQueueCapacity(),
                dtpExecutor.getQueueCapacity(),
                RejectedTypeEnum.formatRejectName(oldProp.getRejectType()),
                RejectedTypeEnum.formatRejectName(dtpExecutor.getRejectHandlerName()),
                receivesStr,
                DateTime.now()
        );
        return highlightNotifyContent(content, diffs);
    }

    /**
     * 突出显示告警内容
     *
     * @param content  内容
     * @param typeEnum 通知类型：配置改变提醒，线程池存活提醒
     * @return
     */
    protected String highlightAlarmContent(String content, NotifyTypeEnum typeEnum) {
        if (StringUtils.isNotBlank(content)) {
            List<String> colorKeys = Lists.newArrayList();
            if (typeEnum == NotifyTypeEnum.REJECT) {
                colorKeys = NotifyHelper.REJECT_ALARM_KEYS;
            } else if (typeEnum == NotifyTypeEnum.CAPACITY) {
                colorKeys = NotifyHelper.CAPACITY_ALARM_KEYS;
            } else if (typeEnum == NotifyTypeEnum.LIVE_NESS) {
                colorKeys = NotifyHelper.LIVENESS_ALARM_KEYS;
            }

            colorKeys.addAll(NotifyHelper.COMMON_ALARM_KEYS);
            Pair<String, String> pair = getColors();
            for (String field : colorKeys) {
                content = content.replace(field, pair.getLeft());
            }
            for (String field : NotifyHelper.ALL_ALARM_KEYS) {
                content = content.replace(field, pair.getRight());
            }
        }
        return content;
    }

    /**
     * 突出显示通知内容
     *
     * @param content 内容
     * @param diffs   变化的key
     * @return
     */
    private String highlightNotifyContent(String content, List<String> diffs) {
        if (StringUtils.isNotBlank(content)) {
            Pair<String, String> pair = getColors();
            for (String field : diffs) {
                content = content.replace(field, pair.getLeft());
            }
            for (Field field : DynamicThreadPoolMainProperty.getMainProps()) {
                content = content.replace(field.getName(), pair.getRight());
            }
        }
        return content;
    }

    /**
     * 告警内容的颜色
     *
     * @return
     */
    protected abstract Pair<String, String> getColors();

    /**
     * 获取线程池名字
     *
     * @param dynamicThreadPoolContext 线程池上下文
     */
    private String getThreadPoolName(DynamicThreadPoolContext dynamicThreadPoolContext) {
        DynamicThreadPoolExecutor dynamicThreadPoolExecutor = dynamicThreadPoolContext.getDynamicThreadPoolExecutor();
        String threadPoolName = "";
        if (Objects.nonNull(dynamicThreadPoolExecutor)) {
            threadPoolName = dynamicThreadPoolExecutor.getThreadPoolName();
        }
        return threadPoolName;
    }
}
